#!/bin/bash
set -e

# edition info
EDITION="debug"
LOG_EXE_FLAG=0
LOG_KEEP_MAX=20
RESET_REASON_MAX=$((1024 * 1024))  # 1M
LOG_TOP_DIR="/tmp/log"
CLOG_CONFIG_JSON="$LOG_TOP_DIR/cfg/config.json"
MODULE_ARR=("general" "camera" "timesync")

log_print(){
    local LOCAL_DATE=`date +%Y-%m-%d-%H-%M-%S`
	if [ $EDITION = "debug" ];then
        echo "[$reset_count] [$LOCAL_DATE] [clog] $1"
	fi
    echo "[$reset_count] [$LOCAL_DATE] [clog] $1" >>$LOG_TOP_DIR/clog.log
}

# $1: reset count
set_reset_count()
{
    if [ -f $LOG_TOP_DIR/reset_count.txt ]; then
        reset_count=$(cat $LOG_TOP_DIR/reset_count.txt)
        if [[ ! $reset_count =~ ^[0-9]+$ ]]; then
            log_print "Invalid reset count value: '$reset_count', resetting to 0"
            reset_count=0
        fi
        reset_count=$((reset_count + 1))
        echo "${reset_count}" > $LOG_TOP_DIR/reset_count.txt
    else
        reset_count=0
        echo "${reset_count}" > $LOG_TOP_DIR/reset_count.txt
    fi

    log_print "set reset count = ${reset_count}"
}

#record reset reason, max is 1M
record_reset_reason()
{
    reset_reason=$1
    if [ -f $LOG_TOP_DIR/reset_reason.txt ]; then
        local file_size=$(wc -c < $LOG_TOP_DIR/reset_reason.txt)
        if [ $file_size -gt $RESET_REASON_MAX ]; then
                mv $LOG_TOP_DIR/reset_reason.txt $LOG_TOP_DIR/reset_reason.txt.old
        fi
    fi
    local LOCAL_DATE=`date +%Y-%m-%d-%H-%M-%S`
    echo "${reset_count}:${LOCAL_DATE}:${reset_reason}" >> $LOG_TOP_DIR/reset_reason.txt

    log_print "record reset reason: ${reset_reason}"
}

# $1: dir path
# return: available space
check_remaining_space()
{
    if [ ! -d "$LOG_TOP_DIR" ]; then
        log_print "Error: Directory $LOG_TOP_DIR does not exist"
        return 1
    fi

    local mount_point=$(df -P "$LOG_TOP_DIR" | tail -n 1 | awk '{print $6}')
    if [ -z "$mount_point" ]; then
        log_print "Error: Failed to get mount point for $LOG_TOP_DIR"
        return 1
    fi

    local available_space=$(df -P "$mount_point" | tail -n 1 | awk '{print $4}')
    if [ -z "$available_space" ] || ! [[ "$available_space" =~ ^[0-9]+$ ]]; then
        log_print "Error: Failed to get available space for $mount_point"
        return 1
    fi

    echo $available_space
}

cleanup_old_logs() {
    local dir_path="$1"

    if [ ! -d "$dir_path" ]; then
        log_print "Warning: Log directory $dir_path not found, cleanup skipped"
        return 1
    fi

    local all_files=$(ls -tp "$dir_path"/* 2>/dev/null | grep -v '/$')
    local file_count=$(echo "$all_files" | wc -l)

    if [ "$file_count" -eq 0 ]; then
        return 0
    fi

    if [ "$file_count" -gt $LOG_KEEP_MAX ]; then
        local excess_count=$((file_count - LOG_KEEP_MAX + 1))
        local oldest_files=$(echo "$all_files" | tail -n "$excess_count")
        echo "$oldest_files" | xargs -I {} rm -f {}
    fi
}

check_first_module_log()
{
    local module_name=$1
    local module_dir=$LOG_TOP_DIR/$module_name
    if [ ! -f $module_dir/message ]; then
        log_print "module dir $module_dir/message is not exit, don't need package"
        return 0
    fi

    for file in "$module_dir"/*; do
        if [ -f "$file" ]; then
            name=$(basename "$file")
            if [[ "$name" =~ ^message(\.[0-9]+)?$ ]]; then
                local size=$(stat -c %s "$file")
                local mtime_raw=$(stat -c %y "$file")
                local mtime=$(date -d "$mtime_raw" +%Y_%m_%d_%H_%M_%S)

                local suffix="${BASH_REMATCH[1]}"
                local seq=""
                if [ -n "$suffix" ]; then
                    seq="${suffix#.}"
                fi

                if [ ! -d $module_dir/archive ]; then
                    mkdir -p $module_dir/archive
                fi

                local f_reset_count=$(printf "%04d" "$reset_count")
                cleanup_old_logs $module_dir/archive
                if [ -n "$seq" ]; then
                    mv $file $module_dir/archive/$module_name-$f_reset_count-$mtime-$seq.log
                else
                    mv $file $module_dir/archive/$module_name-$f_reset_count-$mtime-last.log
                fi
            fi
        fi
    done
}

check_module_log()
{
    local module_name=$1
    local module_dir=$LOG_TOP_DIR/$module_name

    if [ ! -d $module_dir/archive ]; then
        log_print "module dir $module_dir/archive is not exit, create it"
        mkdir -p $module_dir/archive
    fi

    for file in "$module_dir"/*; do
        if [ -f "$file" ]; then
            name=$(basename "$file")
            if [ -z $name ] || [ $name = "message" ]; then
                continue
            fi
            if [[ "$name" =~ ^message\.([0-9]+)?$ ]]; then
                size=$(stat -c %s "$file")
                local mtime_raw=$(stat -c %y "$file")
                local mtime=$(date -d "$mtime_raw" +%Y_%m_%d_%H_%M_%S)

                local suffix="${BASH_REMATCH[1]}"
                local seq="${suffix#.}"

                local f_reset_count=$(printf "%04d" "$reset_count")

                cleanup_old_logs $module_dir/archive
                mv $file $module_dir/archive/$module_name-$f_reset_count-$mtime.log
            fi
        fi
    done
}

check_process_exist()
{
    local process_name=$1
    local existing_pids=$(ps aux | grep "$process_name" | grep -v "grep" | awk '{print $2}')
    if [ -n "$existing_pids" ]; then
        echo "$existing_pids"
        return 0
    else
        return 1
    fi
}

start_clog_test_safely()
{
    local target_dir="${PWD}/out/build/test_package/"
    local process_name="clogd"

    cd "$target_dir" || {
        log_print "Error: Failed to enter directory $target_dir"
        return 1
    }

    local existing_pids=$(ps aux | grep "$process_name" | grep -v "grep" | awk '{print $2}')
    
    if [ -n "$existing_pids" ]; then
        log_print "Found existing $process_name processes: $existing_pids, killing them..."
        kill $existing_pids 2>/dev/null
        sleep 1
    fi

    local new_pid=$(./$process_name clog_config.json > /dev/null & echo $!)
    log_print "[init] Started new $process_name, pid: $new_pid"
}

start_clog_sys()
{
    # create log top dir
    if [ ! -d $LOG_TOP_DIR ]; then
        mkdir -p $LOG_TOP_DIR
    fi

    # set reset count and reset reason
    set_reset_count
    record_reset_reason "start_up"

    # check log dir space is enough
    available_space=$(check_remaining_space)
    if [ $available_space -lt $RESET_REASON_MAX ]; then
        log_print "log dir space is not enough, available space is $available_space bytes"
    else
        log_print "log dir space is enough, available space is $available_space bytes"
    fi

    while :; do
        if [ $LOG_EXE_FLAG -eq 0 ]; then
            if [ $reset_count -gt 0 ]; then
                reset_count=$(expr $reset_count - 1)
                for item in "${MODULE_ARR[@]}"; do
                    check_first_module_log $item
                done
                reset_count=$(expr $reset_count + 1)
                sync
            fi
            LOG_EXE_FLAG=1
            start_clog_test_safely
        fi

        for item in "${MODULE_ARR[@]}"; do
            check_module_log $item
        done
        sleep 10
    done
}

stop_clog_sys()
{
    existing_pids=$(check_process_exist "clogd")
    if [ $? -eq 0 ]; then
        echo "Found existing clogd processes, killing them..."
        for pid in $existing_pids; do
            kill -9 $pid 2>/dev/null
        done
        sleep 1
    fi

    existing_pids=$(check_process_exist "clog-setup")
    if [ $? -eq 0 ]; then
        echo "Found existing clog-setup processes, killing them..."
        for pid in $existing_pids; do
            kill -9 $pid 2>/dev/null
        done
        sleep 1
    fi
}
case "$1" in
  start)
	echo -n "Starting clog daemon log"
    start_clog_sys 2>/dev/null & 
	echo "done"
	;;
  stop)
	echo -n "Stopping clog daemon log: "
    stop_clog_sys
	echo "done"
	;;
  restart)
  	stop_clog_sys
    sleep 1
    start_clog_sys 2>/dev/null &
	;;
  *)
	echo "Usage: hobot-log { start | stop | restart }" >&2
	exit 1
	;;
esac